import {
    EventDispatcher, Mesh, Object3D,
    PerspectiveCamera, Raycaster, Scene, Vector2,
} from "three";

/*全局事件委托
*
* */

export class EventManage extends EventDispatcher {
    private dom: HTMLElement
    private camera: PerspectiveCamera;
    private scene: Scene;
    constructor(params) {
        super();

        this.dom = params.dom;
        this.camera = params.camera;
        this.scene = params.scene;

        const dom = this.dom;
        const camera = this.camera;
        const scene = this.scene;

        //mouse对象用于记录鼠标所移动的位置对应在canvas上的单位向量坐标
        // X分量与Y分量应当在-1到1之间。
        const mouse = new Vector2();

        //射线
        const raycaster: Raycaster = new Raycaster()

        //缓存对象,用于存储鼠标移动的时候, 经过的对象
        let cacheObject: Object3D | null = null;


        //添加 鼠标 down事件
        dom.addEventListener('mousedown', e => {
            //射线 拾取物体
            raycaster.setFromCamera(mouse, camera);
            const intersections = raycaster.intersectObjects(scene.children)

            this.dispatchEvent({
                type: 'mousedown',
                intersections
            })
            if(intersections.length) {
                const object = intersections[0].object;
                object.dispatchEvent({
                    type: 'mousedown'
                })
            }
        })

        //添加 鼠标移动监听事件
        dom.addEventListener('mousemove', e => {
            //    记录该位置在canvas坐标的单位坐标
            mouse.x = e.offsetX * 2 / dom.offsetWidth - 1;
            mouse.y = 1 - e.offsetY * 2 / dom.offsetHeight;

            //参数1： 场景的子元素集合， 参数2： 默认true, 递归，添加物体的后代(该处是全局事件代理类, 因此不设置成false
            raycaster.setFromCamera(mouse, camera);
            const intersections = raycaster.intersectObjects(scene.children);

            this.dispatchEvent({
                type: 'mousemove',
                intersections
            })

            if (intersections.length) {
                const object = intersections[0].object;

                if (object !== cacheObject) {
                    //    缓存对象和当前对象不是同一个
                    // 1.从空白区域移入物体中, 此时 cacheObject = null
                    // 2.从一个物体A移入另一个物体B中, A需要触发移除事件, B需要触发移入事件
                    if (cacheObject) {
                        cacheObject.dispatchEvent({type: 'mouseleave'})
                    }
                    object.dispatchEvent({type: 'mouseenter'})
                    cacheObject = object;
                } else {
                    object.dispatchEvent({type: 'mousemove'})
                }
            } else {
                //    移到空白区域, 调用移出事件, 重置缓存对象
                if (cacheObject) {
                    cacheObject.dispatchEvent({
                        type: 'mouseleave'
                    });
                }
                cacheObject = null;
            }
        })

        //添加 鼠标 up事件
        dom.addEventListener('mouseup', e => {
            //射线 拾取物体
            raycaster.setFromCamera(mouse, camera);
            const intersections = raycaster.intersectObjects(scene.children);
            this.dispatchEvent({
                type: 'mouseup',
                intersections
            })

            if(intersections.length) {
                const object = intersections[0].object;
                object.dispatchEvent({
                    type: 'mouseup'
                })
            }
        })

        dom.addEventListener('click', e => {
            raycaster.setFromCamera(mouse, camera)
            /*射线从相机视角穿透场景时, 变换控制器也是场景中的object3D, 也是会被射线所拾取的, 如何解决该问题
             先移除变换控制器, 待获取到相交的组后再添加回去
             */
            const intersections = raycaster.intersectObjects(scene.children)
            this.dispatchEvent({
                type: 'click',
                intersections
            })

            if(intersections.length) {
                const object = intersections[0].object as Mesh;
                object.dispatchEvent({
                    type: 'click'
                })
            }
        })

    }
}